Advanced Spatial-Temporal EDA: NASA WWW Server Logs

Applied Statistical Inference, Spectral Analysis, and Unsupervised Learning

library(tidyverse)
library(lubridate)
library(MASS)
library(fitdistrplus)
library(WaveletComp)
library(kohonen)
library(dbscan)
library(factoextra)
library(copula)
library(evd)
library(epiR)
library(gridExtra)
library(plotly)

1. Data Loading & Preparation

We load the processed training data and calculate inter-arrival times for distribution analysis.

# Define paths
data_dir <- "../data/processed"
train_path <- file.path(data_dir, "train.csv")

# Load data
df <- read_csv(train_path) %>% 
  mutate(time = as_datetime(time)) %>% 
  arrange(time)

# Calculate inter-arrival times (in seconds)
df <- df %>%
  mutate(inter_arrival = as.numeric(difftime(time, lag(time), units = "secs"))) %>%
  filter(!is.na(inter_arrival))

# Subset for heavy computations (Spectral/Clustering)
set.seed(123)
df_sample <- df %>% sample_n(100000)

2. Parametric Probability Distributions

2.1 Inter-Arrival Times (Exponential/Gamma)

According to queuing theory, inter-arrival times often follow an Exponential or Gamma distribution.

# Filter zero arrivals for Gamma fitting
iat_clean <- df$inter_arrival[df$inter_arrival > 0]

# Fit Exponential
fit_exp <- fitdist(iat_clean, "exp")
# Fit Gamma
fit_gamma <- fitdist(iat_clean, "gamma")

plot(fit_gamma)

summary(fit_gamma)
## Fitting of the distribution ' gamma ' by maximum likelihood 
## Parameters : 
##        estimate   Std. Error
## shape 1.3058813 0.0012543729
## rate  0.5011878 0.0005840945
## Loglikelihood:  -3405448   AIC:  6810901   BIC:  6810925 
## Correlation matrix:
##           shape      rate
## shape 1.0000000 0.8242088
## rate  0.8242088 1.0000000

2.2 Extreme Values (GEV) in Request Sizes

We analyze the distribution of request sizes, specifically looking at the tail behavior using Generalized Extreme Value (GEV) theory.

# Daily Maxima of file sizes
daily_max <- df %>%
  mutate(date = as_date(time)) %>%
  group_by(date) %>%
  summarise(max_size = max(size, na.rm = TRUE))

fit_gev <- evd::fgev(daily_max$max_size, std.err = FALSE)
print(fit_gev)
## 
## Call: evd::fgev(x = daily_max$max_size, std.err = FALSE) 
## Deviance: 1489.068 
## 
## Estimates
##       loc      scale      shape  
## 1.970e+06  8.172e+05  7.829e-03  
## 
## Optimization Information
##   Convergence: successful 
##   Function Evaluations: 19 
##   Gradient Evaluations: 3
# Plotting the GEV distribution against daily maxima
hist(daily_max$max_size, prob = TRUE, main = "Daily Maximum Request Sizes vs. GEV Fit", breaks = 20)
# Accessing estimates properly (they are in fit_gev$estimate)
curve(evd::dgev(x, loc = fit_gev$estimate[1], scale = fit_gev$estimate[2], shape = fit_gev$estimate[3]), add = TRUE, col = "red", lwd = 2)


3. Joint Distributions & Copulas

We explore the dependency between the number of requests (frequency) and the average size of data transferred per hour using a Gaussian Copula.

# Aggregate hourly
hourly_stats <- df %>%
  mutate(hour_bin = floor_date(time, "1 hour")) %>%
  group_by(hour_bin) %>%
  summarise(freq = n(), avg_size = mean(size, na.rm = TRUE))

# Transform to Uniform [0,1]
u_freq <- rank(hourly_stats$freq) / (nrow(hourly_stats) + 1)
u_size <- rank(hourly_stats$avg_size) / (nrow(hourly_stats) + 1)
cop_df <- data.frame(u_freq, u_size)

# Calculate Correlation in Normal space
rho <- cor(qnorm(u_freq), qnorm(u_size), method = "pearson")

# Visualize Copula Space
ggplot(cop_df, aes(x = u_freq, y = u_size)) +
  geom_point(alpha = 0.5, color = "darkgreen") +
  geom_density_2d(color = "black") +
  labs(title = "Gaussian Copula Space (Uniform Marginals)", 
       subtitle = paste("rho =", round(rho, 3)),
       x = "U(Frequency)", y = "U(Avg Size)") +
  theme_minimal()


4. Frequentist Inference & Testing

4.1 Two-Sample t-test: Weekday vs. Weekend

Hypothesis: Does the mean traffic volume per hour differ significantly between weekdays and weekends?

hourly_stats <- hourly_stats %>%
  mutate(is_weekend = wday(hour_bin) %in% c(1, 7))

t_res <- t.test(freq ~ is_weekend, data = hourly_stats)
print(t_res)
## 
##  Welch Two Sample t-test
## 
## data:  freq by is_weekend
## t = 17.345, df = 1144.6, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group FALSE and group TRUE is not equal to 0
## 95 percent confidence interval:
##  1059.372 1329.616
## sample estimates:
## mean in group FALSE  mean in group TRUE 
##            2893.565            1699.071
ggplot(hourly_stats, aes(x = is_weekend, y = freq, fill = is_weekend)) +
  geom_boxplot() +
  labs(title = "Hourly Requests: Weekday vs. Weekend", x = "Is Weekend", y = "Hits/Hour") +
  theme_minimal()


5. Discrete Predictands & Forecast Verification

We define a “High Load” event as an hour where traffic exceeds the 90th percentile. We evaluate a simple persistence forecast (If previous hour was High Load, next hour will be).

threshold <- quantile(hourly_stats$freq, 0.90)
hourly_stats <- hourly_stats %>%
  mutate(obs_high = ifelse(freq > threshold, 1, 0),
         pred_high = lag(obs_high, default = 0))

# 2x2 Contingency Table
skill_tab <- table(factor(hourly_stats$pred_high, levels = c(1, 0)), 
                   factor(hourly_stats$obs_high, levels = c(1, 0)))

# Calculate Skill Scores
a <- skill_tab[1, 1]; b <- skill_tab[1, 2]; c <- skill_tab[2, 1]; d <- skill_tab[2, 2]; n <- sum(skill_tab)
pc <- (a + d) / n
bias <- (a + b) / (a + c)
pod <- a / (a + c)
far <- b / (a + b)
hss <- 2 * (a * d - b * c) / ((a + c) * (c + d) + (a + b) * (b + d))

cat("Accuracy (PC):", round(pc, 3), "
")
## Accuracy (PC): 0.946
cat("Bias Score:", round(bias, 3), "
")
## Bias Score: 1
cat("Hit Rate (POD):", round(pod, 3), "
")
## Hit Rate (POD): 0.733
cat("False Alarm Ratio (FAR):", round(far, 3), "
")
## False Alarm Ratio (FAR): 0.267
cat("Heidke Skill Score (HSS):", round(hss, 3), "
")
## Heidke Skill Score (HSS): 0.703

6. Spectral & Wavelet Analysis

We analyze the periodicity of traffic hits (15-minute resolution) to identify rhythms.

# Aggregate 15m
ts_15m <- df %>%
  mutate(time_15 = floor_date(time, "15 minutes")) %>%
  group_by(time_15) %>%
  summarise(hits = n())

# Wavelet Transform
w_res <- analyze.wavelet(ts_15m, "hits", dt = 1, loess.span = 0, verbose = FALSE)
##   |                                                                              |                                                                      |   0%  |                                                                              |=                                                                     |   1%  |                                                                              |=                                                                     |   2%  |                                                                              |==                                                                    |   3%  |                                                                              |===                                                                   |   4%  |                                                                              |====                                                                  |   5%  |                                                                              |====                                                                  |   6%  |                                                                              |=====                                                                 |   7%  |                                                                              |======                                                                |   8%  |                                                                              |======                                                                |   9%  |                                                                              |=======                                                               |  10%  |                                                                              |========                                                              |  11%  |                                                                              |========                                                              |  12%  |                                                                              |=========                                                             |  13%  |                                                                              |==========                                                            |  14%  |                                                                              |==========                                                            |  15%  |                                                                              |===========                                                           |  16%  |                                                                              |============                                                          |  17%  |                                                                              |=============                                                         |  18%  |                                                                              |=============                                                         |  19%  |                                                                              |==============                                                        |  20%  |                                                                              |===============                                                       |  21%  |                                                                              |===============                                                       |  22%  |                                                                              |================                                                      |  23%  |                                                                              |=================                                                     |  24%  |                                                                              |==================                                                    |  25%  |                                                                              |==================                                                    |  26%  |                                                                              |===================                                                   |  27%  |                                                                              |====================                                                  |  28%  |                                                                              |====================                                                  |  29%  |                                                                              |=====================                                                 |  30%  |                                                                              |======================                                                |  31%  |                                                                              |======================                                                |  32%  |                                                                              |=======================                                               |  33%  |                                                                              |========================                                              |  34%  |                                                                              |========================                                              |  35%  |                                                                              |=========================                                             |  36%  |                                                                              |==========================                                            |  37%  |                                                                              |===========================                                           |  38%  |                                                                              |===========================                                           |  39%  |                                                                              |============================                                          |  40%  |                                                                              |=============================                                         |  41%  |                                                                              |=============================                                         |  42%  |                                                                              |==============================                                        |  43%  |                                                                              |===============================                                       |  44%  |                                                                              |================================                                      |  45%  |                                                                              |================================                                      |  46%  |                                                                              |=================================                                     |  47%  |                                                                              |==================================                                    |  48%  |                                                                              |==================================                                    |  49%  |                                                                              |===================================                                   |  50%  |                                                                              |====================================                                  |  51%  |                                                                              |====================================                                  |  52%  |                                                                              |=====================================                                 |  53%  |                                                                              |======================================                                |  54%  |                                                                              |======================================                                |  55%  |                                                                              |=======================================                               |  56%  |                                                                              |========================================                              |  57%  |                                                                              |=========================================                             |  58%  |                                                                              |=========================================                             |  59%  |                                                                              |==========================================                            |  60%  |                                                                              |===========================================                           |  61%  |                                                                              |===========================================                           |  62%  |                                                                              |============================================                          |  63%  |                                                                              |=============================================                         |  64%  |                                                                              |==============================================                        |  65%  |                                                                              |==============================================                        |  66%  |                                                                              |===============================================                       |  67%  |                                                                              |================================================                      |  68%  |                                                                              |================================================                      |  69%  |                                                                              |=================================================                     |  70%  |                                                                              |==================================================                    |  71%  |                                                                              |==================================================                    |  72%  |                                                                              |===================================================                   |  73%  |                                                                              |====================================================                  |  74%  |                                                                              |====================================================                  |  75%  |                                                                              |=====================================================                 |  76%  |                                                                              |======================================================                |  77%  |                                                                              |=======================================================               |  78%  |                                                                              |=======================================================               |  79%  |                                                                              |========================================================              |  80%  |                                                                              |=========================================================             |  81%  |                                                                              |=========================================================             |  82%  |                                                                              |==========================================================            |  83%  |                                                                              |===========================================================           |  84%  |                                                                              |============================================================          |  85%  |                                                                              |============================================================          |  86%  |                                                                              |=============================================================         |  87%  |                                                                              |==============================================================        |  88%  |                                                                              |==============================================================        |  89%  |                                                                              |===============================================================       |  90%  |                                                                              |================================================================      |  91%  |                                                                              |================================================================      |  92%  |                                                                              |=================================================================     |  93%  |                                                                              |==================================================================    |  94%  |                                                                              |==================================================================    |  95%  |                                                                              |===================================================================   |  96%  |                                                                              |====================================================================  |  97%  |                                                                              |===================================================================== |  98%  |                                                                              |===================================================================== |  99%  |                                                                              |======================================================================| 100%
# Average Power Spectrum
wt.avg(w_res, main = "Average Wavelet Power (Periodicity Analysis)")

# Scalogram (Subset for visualization clarity)
wt.image(w_res, main = "Wavelet Scalogram (Time-Frequency)")


7. Unsupervised Learning: IP Behavior Profiling

We profile IPs based on their average request size, frequency, and error rate, then cluster them.

ip_profile <- df %>%
  group_by(ip) %>%
  summarise(
    total_req = n(),
    avg_size = mean(size, na.rm = TRUE),
    error_rate = sum(status_label != "Success", na.rm = TRUE) / n()
  ) %>%
  filter(total_req > 10) %>% # Filter noise
  na.omit() %>%
  column_to_rownames("ip")

# Scale for clustering/PCA/SOM
ip_scaled <- scale(ip_profile)
# Remove columns that became NaN due to zero variance
ip_scaled <- ip_scaled[, colSums(is.na(ip_scaled)) == 0]

# 7.1 PCA
pca_res <- prcomp(ip_scaled)
fviz_pca_biplot(pca_res, label = "var", title = "PCA of IP Behaviors")

# 7.2 K-Means Clustering
set.seed(123)
km_res <- kmeans(ip_scaled, centers = 4, nstart = 25)
fviz_cluster(km_res, data = ip_scaled, geom = "point", title = "K-Means: IP Behavior Clusters")

# 7.3 SOM (Self-Organizing Maps)
som_grid <- somgrid(xdim = 5, ydim = 5, topo = "hexagonal")
som_model <- som(ip_scaled, grid = som_grid, rlen = 100)
plot(som_model, type = "codes", main = "SOM: IP Behavior Archetypes")

8. Conclusion

This advanced EDA reveals: 1. Stationarity: Traffic exhibits strong daily cycles (confirmed by Wavelet peaks at ~96 periods for 15m data). 2. IP Archetypes: Clustering and SOM identified distinct groups of users (High Bandwidth vs. High Error vs. Standard). 3. Forecasting: Persistence is a moderately strong baseline for load prediction (HSS > 0). 4. Extremes: Request sizes follow an Extreme Value distribution, indicating the risk of very large bursts.

LS0tCnRpdGxlOiAiQWR2YW5jZWQgU3BhdGlhbC1UZW1wb3JhbCBFREE6IE5BU0EgV1dXIFNlcnZlciBMb2dzIgpzdWJ0aXRsZTogIkFwcGxpZWQgU3RhdGlzdGljYWwgSW5mZXJlbmNlLCBTcGVjdHJhbCBBbmFseXNpcywgYW5kIFVuc3VwZXJ2aXNlZCBMZWFybmluZyIKYXV0aG9yOiAiTmd1eWVuIExhbSBUdW5nIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogCiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246CiAgICBoaWdobGlnaHQ6IGVzcHJlc3NvCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIHRvY19kZXB0aDogMwotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmaWcuZGltID0gYygxMCwgNyksIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBvdXQud2lkdGggPSAiMTAwJSIsIGZpZy5wYXRoID0gInJwbG90cy8iKQpgYGAKCmBgYHtyIGxpYnJhcmllc30KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkoZml0ZGlzdHJwbHVzKQpsaWJyYXJ5KFdhdmVsZXRDb21wKQpsaWJyYXJ5KGtvaG9uZW4pCmxpYnJhcnkoZGJzY2FuKQpsaWJyYXJ5KGZhY3RvZXh0cmEpCmxpYnJhcnkoY29wdWxhKQpsaWJyYXJ5KGV2ZCkKbGlicmFyeShlcGlSKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShwbG90bHkpCmBgYAoKIyAxLiBEYXRhIExvYWRpbmcgJiBQcmVwYXJhdGlvbgoKV2UgbG9hZCB0aGUgcHJvY2Vzc2VkIHRyYWluaW5nIGRhdGEgYW5kIGNhbGN1bGF0ZSBpbnRlci1hcnJpdmFsIHRpbWVzIGZvciBkaXN0cmlidXRpb24gYW5hbHlzaXMuCgpgYGB7ciBsb2FkX2RhdGF9CiMgRGVmaW5lIHBhdGhzCmRhdGFfZGlyIDwtICIuLi9kYXRhL3Byb2Nlc3NlZCIKdHJhaW5fcGF0aCA8LSBmaWxlLnBhdGgoZGF0YV9kaXIsICJ0cmFpbi5jc3YiKQoKIyBMb2FkIGRhdGEKZGYgPC0gcmVhZF9jc3YodHJhaW5fcGF0aCkgJT4lIAogIG11dGF0ZSh0aW1lID0gYXNfZGF0ZXRpbWUodGltZSkpICU+JSAKICBhcnJhbmdlKHRpbWUpCgojIENhbGN1bGF0ZSBpbnRlci1hcnJpdmFsIHRpbWVzIChpbiBzZWNvbmRzKQpkZiA8LSBkZiAlPiUKICBtdXRhdGUoaW50ZXJfYXJyaXZhbCA9IGFzLm51bWVyaWMoZGlmZnRpbWUodGltZSwgbGFnKHRpbWUpLCB1bml0cyA9ICJzZWNzIikpKSAlPiUKICBmaWx0ZXIoIWlzLm5hKGludGVyX2Fycml2YWwpKQoKIyBTdWJzZXQgZm9yIGhlYXZ5IGNvbXB1dGF0aW9ucyAoU3BlY3RyYWwvQ2x1c3RlcmluZykKc2V0LnNlZWQoMTIzKQpkZl9zYW1wbGUgPC0gZGYgJT4lIHNhbXBsZV9uKDEwMDAwMCkKYGBgCgotLS0KCiMgMi4gUGFyYW1ldHJpYyBQcm9iYWJpbGl0eSBEaXN0cmlidXRpb25zCgojIyAyLjEgSW50ZXItQXJyaXZhbCBUaW1lcyAoRXhwb25lbnRpYWwvR2FtbWEpCkFjY29yZGluZyB0byBxdWV1aW5nIHRoZW9yeSwgaW50ZXItYXJyaXZhbCB0aW1lcyBvZnRlbiBmb2xsb3cgYW4gRXhwb25lbnRpYWwgb3IgR2FtbWEgZGlzdHJpYnV0aW9uLgoKYGBge3IgaW50ZXJfYXJyaXZhbF9kaXN0fQojIEZpbHRlciB6ZXJvIGFycml2YWxzIGZvciBHYW1tYSBmaXR0aW5nCmlhdF9jbGVhbiA8LSBkZiRpbnRlcl9hcnJpdmFsW2RmJGludGVyX2Fycml2YWwgPiAwXQoKIyBGaXQgRXhwb25lbnRpYWwKZml0X2V4cCA8LSBmaXRkaXN0KGlhdF9jbGVhbiwgImV4cCIpCiMgRml0IEdhbW1hCmZpdF9nYW1tYSA8LSBmaXRkaXN0KGlhdF9jbGVhbiwgImdhbW1hIikKCnBsb3QoZml0X2dhbW1hKQpzdW1tYXJ5KGZpdF9nYW1tYSkKYGBgCgojIyAyLjIgRXh0cmVtZSBWYWx1ZXMgKEdFVikgaW4gUmVxdWVzdCBTaXplcwpXZSBhbmFseXplIHRoZSBkaXN0cmlidXRpb24gb2YgcmVxdWVzdCBzaXplcywgc3BlY2lmaWNhbGx5IGxvb2tpbmcgYXQgdGhlIHRhaWwgYmVoYXZpb3IgdXNpbmcgR2VuZXJhbGl6ZWQgRXh0cmVtZSBWYWx1ZSAoR0VWKSB0aGVvcnkuCgpgYGB7ciBzaXplX2V2ZH0KIyBEYWlseSBNYXhpbWEgb2YgZmlsZSBzaXplcwpkYWlseV9tYXggPC0gZGYgJT4lCiAgbXV0YXRlKGRhdGUgPSBhc19kYXRlKHRpbWUpKSAlPiUKICBncm91cF9ieShkYXRlKSAlPiUKICBzdW1tYXJpc2UobWF4X3NpemUgPSBtYXgoc2l6ZSwgbmEucm0gPSBUUlVFKSkKCmZpdF9nZXYgPC0gZXZkOjpmZ2V2KGRhaWx5X21heCRtYXhfc2l6ZSwgc3RkLmVyciA9IEZBTFNFKQpwcmludChmaXRfZ2V2KQoKIyBQbG90dGluZyB0aGUgR0VWIGRpc3RyaWJ1dGlvbiBhZ2FpbnN0IGRhaWx5IG1heGltYQpoaXN0KGRhaWx5X21heCRtYXhfc2l6ZSwgcHJvYiA9IFRSVUUsIG1haW4gPSAiRGFpbHkgTWF4aW11bSBSZXF1ZXN0IFNpemVzIHZzLiBHRVYgRml0IiwgYnJlYWtzID0gMjApCiMgQWNjZXNzaW5nIGVzdGltYXRlcyBwcm9wZXJseSAodGhleSBhcmUgaW4gZml0X2dldiRlc3RpbWF0ZSkKY3VydmUoZXZkOjpkZ2V2KHgsIGxvYyA9IGZpdF9nZXYkZXN0aW1hdGVbMV0sIHNjYWxlID0gZml0X2dldiRlc3RpbWF0ZVsyXSwgc2hhcGUgPSBmaXRfZ2V2JGVzdGltYXRlWzNdKSwgYWRkID0gVFJVRSwgY29sID0gInJlZCIsIGx3ZCA9IDIpCmBgYAoKLS0tCgojIDMuIEpvaW50IERpc3RyaWJ1dGlvbnMgJiBDb3B1bGFzCgpXZSBleHBsb3JlIHRoZSBkZXBlbmRlbmN5IGJldHdlZW4gdGhlIG51bWJlciBvZiByZXF1ZXN0cyAoZnJlcXVlbmN5KSBhbmQgdGhlIGF2ZXJhZ2Ugc2l6ZSBvZiBkYXRhIHRyYW5zZmVycmVkIHBlciBob3VyIHVzaW5nIGEgR2F1c3NpYW4gQ29wdWxhLgoKYGBge3IgY29wdWxhX2FuYWx5c2lzfQojIEFnZ3JlZ2F0ZSBob3VybHkKaG91cmx5X3N0YXRzIDwtIGRmICU+JQogIG11dGF0ZShob3VyX2JpbiA9IGZsb29yX2RhdGUodGltZSwgIjEgaG91ciIpKSAlPiUKICBncm91cF9ieShob3VyX2JpbikgJT4lCiAgc3VtbWFyaXNlKGZyZXEgPSBuKCksIGF2Z19zaXplID0gbWVhbihzaXplLCBuYS5ybSA9IFRSVUUpKQoKIyBUcmFuc2Zvcm0gdG8gVW5pZm9ybSBbMCwxXQp1X2ZyZXEgPC0gcmFuayhob3VybHlfc3RhdHMkZnJlcSkgLyAobnJvdyhob3VybHlfc3RhdHMpICsgMSkKdV9zaXplIDwtIHJhbmsoaG91cmx5X3N0YXRzJGF2Z19zaXplKSAvIChucm93KGhvdXJseV9zdGF0cykgKyAxKQpjb3BfZGYgPC0gZGF0YS5mcmFtZSh1X2ZyZXEsIHVfc2l6ZSkKCiMgQ2FsY3VsYXRlIENvcnJlbGF0aW9uIGluIE5vcm1hbCBzcGFjZQpyaG8gPC0gY29yKHFub3JtKHVfZnJlcSksIHFub3JtKHVfc2l6ZSksIG1ldGhvZCA9ICJwZWFyc29uIikKCiMgVmlzdWFsaXplIENvcHVsYSBTcGFjZQpnZ3Bsb3QoY29wX2RmLCBhZXMoeCA9IHVfZnJlcSwgeSA9IHVfc2l6ZSkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC41LCBjb2xvciA9ICJkYXJrZ3JlZW4iKSArCiAgZ2VvbV9kZW5zaXR5XzJkKGNvbG9yID0gImJsYWNrIikgKwogIGxhYnModGl0bGUgPSAiR2F1c3NpYW4gQ29wdWxhIFNwYWNlIChVbmlmb3JtIE1hcmdpbmFscykiLCAKICAgICAgIHN1YnRpdGxlID0gcGFzdGUoInJobyA9Iiwgcm91bmQocmhvLCAzKSksCiAgICAgICB4ID0gIlUoRnJlcXVlbmN5KSIsIHkgPSAiVShBdmcgU2l6ZSkiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKLS0tCgojIDQuIEZyZXF1ZW50aXN0IEluZmVyZW5jZSAmIFRlc3RpbmcKCiMjIDQuMSBUd28tU2FtcGxlIHQtdGVzdDogV2Vla2RheSB2cy4gV2Vla2VuZAoqKkh5cG90aGVzaXMqKjogRG9lcyB0aGUgbWVhbiB0cmFmZmljIHZvbHVtZSBwZXIgaG91ciBkaWZmZXIgc2lnbmlmaWNhbnRseSBiZXR3ZWVuIHdlZWtkYXlzIGFuZCB3ZWVrZW5kcz8KCmBgYHtyIHRfdGVzdF90cmFmZmljfQpob3VybHlfc3RhdHMgPC0gaG91cmx5X3N0YXRzICU+JQogIG11dGF0ZShpc193ZWVrZW5kID0gd2RheShob3VyX2JpbikgJWluJSBjKDEsIDcpKQoKdF9yZXMgPC0gdC50ZXN0KGZyZXEgfiBpc193ZWVrZW5kLCBkYXRhID0gaG91cmx5X3N0YXRzKQpwcmludCh0X3JlcykKCmdncGxvdChob3VybHlfc3RhdHMsIGFlcyh4ID0gaXNfd2Vla2VuZCwgeSA9IGZyZXEsIGZpbGwgPSBpc193ZWVrZW5kKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBsYWJzKHRpdGxlID0gIkhvdXJseSBSZXF1ZXN0czogV2Vla2RheSB2cy4gV2Vla2VuZCIsIHggPSAiSXMgV2Vla2VuZCIsIHkgPSAiSGl0cy9Ib3VyIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCi0tLQoKIyA1LiBEaXNjcmV0ZSBQcmVkaWN0YW5kcyAmIEZvcmVjYXN0IFZlcmlmaWNhdGlvbgoKV2UgZGVmaW5lIGEgIkhpZ2ggTG9hZCIgZXZlbnQgYXMgYW4gaG91ciB3aGVyZSB0cmFmZmljIGV4Y2VlZHMgdGhlIDkwdGggcGVyY2VudGlsZS4gV2UgZXZhbHVhdGUgYSBzaW1wbGUgcGVyc2lzdGVuY2UgZm9yZWNhc3QgKElmIHByZXZpb3VzIGhvdXIgd2FzIEhpZ2ggTG9hZCwgbmV4dCBob3VyIHdpbGwgYmUpLgoKYGBge3IgZm9yZWNhc3RfdmVyaWZpY2F0aW9ufQp0aHJlc2hvbGQgPC0gcXVhbnRpbGUoaG91cmx5X3N0YXRzJGZyZXEsIDAuOTApCmhvdXJseV9zdGF0cyA8LSBob3VybHlfc3RhdHMgJT4lCiAgbXV0YXRlKG9ic19oaWdoID0gaWZlbHNlKGZyZXEgPiB0aHJlc2hvbGQsIDEsIDApLAogICAgICAgICBwcmVkX2hpZ2ggPSBsYWcob2JzX2hpZ2gsIGRlZmF1bHQgPSAwKSkKCiMgMngyIENvbnRpbmdlbmN5IFRhYmxlCnNraWxsX3RhYiA8LSB0YWJsZShmYWN0b3IoaG91cmx5X3N0YXRzJHByZWRfaGlnaCwgbGV2ZWxzID0gYygxLCAwKSksIAogICAgICAgICAgICAgICAgICAgZmFjdG9yKGhvdXJseV9zdGF0cyRvYnNfaGlnaCwgbGV2ZWxzID0gYygxLCAwKSkpCgojIENhbGN1bGF0ZSBTa2lsbCBTY29yZXMKYSA8LSBza2lsbF90YWJbMSwgMV07IGIgPC0gc2tpbGxfdGFiWzEsIDJdOyBjIDwtIHNraWxsX3RhYlsyLCAxXTsgZCA8LSBza2lsbF90YWJbMiwgMl07IG4gPC0gc3VtKHNraWxsX3RhYikKcGMgPC0gKGEgKyBkKSAvIG4KYmlhcyA8LSAoYSArIGIpIC8gKGEgKyBjKQpwb2QgPC0gYSAvIChhICsgYykKZmFyIDwtIGIgLyAoYSArIGIpCmhzcyA8LSAyICogKGEgKiBkIC0gYiAqIGMpIC8gKChhICsgYykgKiAoYyArIGQpICsgKGEgKyBiKSAqIChiICsgZCkpCgpjYXQoIkFjY3VyYWN5IChQQyk6Iiwgcm91bmQocGMsIDMpLCAiCiIpCmNhdCgiQmlhcyBTY29yZToiLCByb3VuZChiaWFzLCAzKSwgIgoiKQpjYXQoIkhpdCBSYXRlIChQT0QpOiIsIHJvdW5kKHBvZCwgMyksICIKIikKY2F0KCJGYWxzZSBBbGFybSBSYXRpbyAoRkFSKToiLCByb3VuZChmYXIsIDMpLCAiCiIpCmNhdCgiSGVpZGtlIFNraWxsIFNjb3JlIChIU1MpOiIsIHJvdW5kKGhzcywgMyksICIKIikKYGBgCgotLS0KCiMgNi4gU3BlY3RyYWwgJiBXYXZlbGV0IEFuYWx5c2lzCgpXZSBhbmFseXplIHRoZSBwZXJpb2RpY2l0eSBvZiB0cmFmZmljIGhpdHMgKDE1LW1pbnV0ZSByZXNvbHV0aW9uKSB0byBpZGVudGlmeSByaHl0aG1zLgoKYGBge3Igd2F2ZWxldF9hbmFseXNpc30KIyBBZ2dyZWdhdGUgMTVtCnRzXzE1bSA8LSBkZiAlPiUKICBtdXRhdGUodGltZV8xNSA9IGZsb29yX2RhdGUodGltZSwgIjE1IG1pbnV0ZXMiKSkgJT4lCiAgZ3JvdXBfYnkodGltZV8xNSkgJT4lCiAgc3VtbWFyaXNlKGhpdHMgPSBuKCkpCgojIFdhdmVsZXQgVHJhbnNmb3JtCndfcmVzIDwtIGFuYWx5emUud2F2ZWxldCh0c18xNW0sICJoaXRzIiwgZHQgPSAxLCBsb2Vzcy5zcGFuID0gMCwgdmVyYm9zZSA9IEZBTFNFKQoKIyBBdmVyYWdlIFBvd2VyIFNwZWN0cnVtCnd0LmF2Zyh3X3JlcywgbWFpbiA9ICJBdmVyYWdlIFdhdmVsZXQgUG93ZXIgKFBlcmlvZGljaXR5IEFuYWx5c2lzKSIpCgojIFNjYWxvZ3JhbSAoU3Vic2V0IGZvciB2aXN1YWxpemF0aW9uIGNsYXJpdHkpCnd0LmltYWdlKHdfcmVzLCBtYWluID0gIldhdmVsZXQgU2NhbG9ncmFtIChUaW1lLUZyZXF1ZW5jeSkiKQpgYGAKCi0tLQoKIyA3LiBVbnN1cGVydmlzZWQgTGVhcm5pbmc6IElQIEJlaGF2aW9yIFByb2ZpbGluZwoKV2UgcHJvZmlsZSBJUHMgYmFzZWQgb24gdGhlaXIgYXZlcmFnZSByZXF1ZXN0IHNpemUsIGZyZXF1ZW5jeSwgYW5kIGVycm9yIHJhdGUsIHRoZW4gY2x1c3RlciB0aGVtLgoKYGBge3IgaXBfcHJvZmlsaW5nfQppcF9wcm9maWxlIDwtIGRmICU+JQogIGdyb3VwX2J5KGlwKSAlPiUKICBzdW1tYXJpc2UoCiAgICB0b3RhbF9yZXEgPSBuKCksCiAgICBhdmdfc2l6ZSA9IG1lYW4oc2l6ZSwgbmEucm0gPSBUUlVFKSwKICAgIGVycm9yX3JhdGUgPSBzdW0oc3RhdHVzX2xhYmVsICE9ICJTdWNjZXNzIiwgbmEucm0gPSBUUlVFKSAvIG4oKQogICkgJT4lCiAgZmlsdGVyKHRvdGFsX3JlcSA+IDEwKSAlPiUgIyBGaWx0ZXIgbm9pc2UKICBuYS5vbWl0KCkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJpcCIpCgojIFNjYWxlIGZvciBjbHVzdGVyaW5nL1BDQS9TT00KaXBfc2NhbGVkIDwtIHNjYWxlKGlwX3Byb2ZpbGUpCiMgUmVtb3ZlIGNvbHVtbnMgdGhhdCBiZWNhbWUgTmFOIGR1ZSB0byB6ZXJvIHZhcmlhbmNlCmlwX3NjYWxlZCA8LSBpcF9zY2FsZWRbLCBjb2xTdW1zKGlzLm5hKGlwX3NjYWxlZCkpID09IDBdCgojIDcuMSBQQ0EKcGNhX3JlcyA8LSBwcmNvbXAoaXBfc2NhbGVkKQpmdml6X3BjYV9iaXBsb3QocGNhX3JlcywgbGFiZWwgPSAidmFyIiwgdGl0bGUgPSAiUENBIG9mIElQIEJlaGF2aW9ycyIpCgojIDcuMiBLLU1lYW5zIENsdXN0ZXJpbmcKc2V0LnNlZWQoMTIzKQprbV9yZXMgPC0ga21lYW5zKGlwX3NjYWxlZCwgY2VudGVycyA9IDQsIG5zdGFydCA9IDI1KQpmdml6X2NsdXN0ZXIoa21fcmVzLCBkYXRhID0gaXBfc2NhbGVkLCBnZW9tID0gInBvaW50IiwgdGl0bGUgPSAiSy1NZWFuczogSVAgQmVoYXZpb3IgQ2x1c3RlcnMiKQoKIyA3LjMgU09NIChTZWxmLU9yZ2FuaXppbmcgTWFwcykKc29tX2dyaWQgPC0gc29tZ3JpZCh4ZGltID0gNSwgeWRpbSA9IDUsIHRvcG8gPSAiaGV4YWdvbmFsIikKc29tX21vZGVsIDwtIHNvbShpcF9zY2FsZWQsIGdyaWQgPSBzb21fZ3JpZCwgcmxlbiA9IDEwMCkKcGxvdChzb21fbW9kZWwsIHR5cGUgPSAiY29kZXMiLCBtYWluID0gIlNPTTogSVAgQmVoYXZpb3IgQXJjaGV0eXBlcyIpCmBgYAoKIyA4LiBDb25jbHVzaW9uCgpUaGlzIGFkdmFuY2VkIEVEQSByZXZlYWxzOgoxLiAgKipTdGF0aW9uYXJpdHkqKjogVHJhZmZpYyBleGhpYml0cyBzdHJvbmcgZGFpbHkgY3ljbGVzIChjb25maXJtZWQgYnkgV2F2ZWxldCBwZWFrcyBhdCB+OTYgcGVyaW9kcyBmb3IgMTVtIGRhdGEpLgoyLiAgKipJUCBBcmNoZXR5cGVzKio6IENsdXN0ZXJpbmcgYW5kIFNPTSBpZGVudGlmaWVkIGRpc3RpbmN0IGdyb3VwcyBvZiB1c2VycyAoSGlnaCBCYW5kd2lkdGggdnMuIEhpZ2ggRXJyb3IgdnMuIFN0YW5kYXJkKS4KMy4gICoqRm9yZWNhc3RpbmcqKjogUGVyc2lzdGVuY2UgaXMgYSBtb2RlcmF0ZWx5IHN0cm9uZyBiYXNlbGluZSBmb3IgbG9hZCBwcmVkaWN0aW9uIChIU1MgPiAwKS4KNC4gICoqRXh0cmVtZXMqKjogUmVxdWVzdCBzaXplcyBmb2xsb3cgYW4gRXh0cmVtZSBWYWx1ZSBkaXN0cmlidXRpb24sIGluZGljYXRpbmcgdGhlIHJpc2sgb2YgdmVyeSBsYXJnZSBidXJzdHMuCg==